home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / innd / newsfeeds.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  13KB  |  541 lines

  1. /*  $Revision: 1.31 $
  2. **
  3. **  Routines for the in-core data structures for the newsfeeds file.
  4. */
  5. #include "innd.h"
  6.  
  7.  
  8. STATIC SITE    SITEnull;
  9. STATIC char    SITEfeedspath[] = _PATH_NEWSFEEDS;
  10.  
  11.  
  12. /*
  13. **  Return a copy of an array of strings.
  14. */
  15. STATIC char **
  16. SITEcopystrings(av)
  17.     char    **av;
  18. {
  19.     register char    **new;
  20.     register char    **pp;
  21.     char        **save;
  22.  
  23.     for (pp = av; *pp; pp++)
  24.     continue;
  25.     for (new = save = NEW(char*, pp - av + 1), pp = av; *pp; pp++)
  26.     *new++ = COPY(*pp);
  27.     *new = NULL;
  28.     return save;
  29. }
  30.  
  31.  
  32. /*
  33. **  Read the newsfeeds file, return a string array of entries.
  34. */
  35. char **
  36. SITEreadfile(ReadOnly)
  37.     BOOL        ReadOnly;
  38. {
  39.     static char        **old_strings;
  40.     static time_t    old_mtime;
  41.     static ino_t    old_ino;
  42.     static off_t    old_size;
  43.     register char    *p;
  44.     register char    *to;
  45.     register char    *site;
  46.     register int    i;
  47.     struct stat        Sb;
  48.     char        *data;
  49.  
  50.     if (old_strings != NULL) {
  51.     /* If the file hasn't changed, return a copy of the old data. */
  52.     if (stat(SITEfeedspath, &Sb) >= 0
  53.      && Sb.st_ino == old_ino
  54.      && Sb.st_size == old_size
  55.      && Sb.st_mtime == old_mtime)
  56.         return ReadOnly ? old_strings : SITEcopystrings(old_strings);
  57.  
  58.     /* Data's bad, toss it. */
  59.     for (i = 0; old_strings[i] != NULL; i++)
  60.         DISPOSE(old_strings[i]);
  61.     DISPOSE(old_strings);
  62.     }
  63.  
  64.     /* Read in the file, note its statistics. */
  65.     if ((data = ReadInFile(SITEfeedspath, &Sb)) == NULL) {
  66.     syslog(L_FATAL, "%s cant read %s %m", LogName, SITEfeedspath);
  67.     exit(1);
  68.     }
  69.     old_mtime = Sb.st_mtime;
  70.     old_ino = Sb.st_ino;
  71.     old_size = Sb.st_size;
  72.  
  73.     /* Get a gross count of the number of sites. */
  74.     for (p = data, i = 0; (p = strchr(p, '\n')) != NULL; p++, i++)
  75.     continue;
  76.  
  77.     /* Scan the file, parse all multi-line entries. */
  78.     for (old_strings = NEW(char*, i + 1), i = 0, to = p = data; *p; ) {
  79.     for (site = to; *p; ) {
  80.         if (*p == '\n') {
  81.         p++;
  82.         *to = '\0';
  83.         break;
  84.         }
  85.         if (*p == '\\' && p[1] == '\n')
  86.         while (*++p && CTYPE(isspace, *p))
  87.             continue;
  88.         else
  89.         *to++ = *p++;
  90.     }
  91.     *to++ = '\0';
  92.     if (*site == COMMENT_CHAR || *site == '\0')
  93.         continue;
  94.     old_strings[i++] = COPY(site);
  95.     }
  96.     old_strings[i] = NULL;
  97.  
  98.     DISPOSE(data);
  99.     return ReadOnly ? old_strings : SITEcopystrings(old_strings);
  100. }
  101.  
  102.  
  103. /*
  104. **  Modify "subbed" according to the patterns in "patlist."
  105. */
  106. STATIC void
  107. SITEsetlist(patlist, subbed)
  108.     char        **patlist;
  109.     char        *subbed;
  110. {
  111.     register char    *pat;
  112.     register char    *p;
  113.     register char    subvalue;
  114.     register NEWSGROUP    *ngp;
  115.     register int    i;
  116.  
  117.     while ((pat = *patlist++) != NULL) {
  118.     subvalue = *pat != SUB_NEGATE;
  119.     if (!subvalue)
  120.         pat++;
  121.  
  122.     /* See if pattern is a simple newsgroup name.  If so, set the
  123.      * right subbed element for that one group (if found); if not,
  124.      * pattern-match against all the groups. */
  125.     for (p = pat; *p; p++)
  126.         if (*p == '?' || *p == '*' || *p == '[')
  127.         break;
  128.     if (*p == '\0') {
  129.         /* Simple string; look it up, set it. */
  130.         if ((ngp = NGfind(pat)) != NULL)
  131.         subbed[ngp - Groups] = subvalue;
  132.     }
  133.     else
  134.         for (p = subbed, ngp = Groups, i = nGroups; --i >= 0; ngp++, p++)
  135.         if (wildmat(ngp->Name, pat))
  136.             *p = subvalue;
  137.     }
  138. }
  139.  
  140.  
  141. /*
  142. **  Parse an individual site entry.  Subbed is used to build the subscription
  143. **  list.  Since this routine is called once for each site, the caller
  144. **  allocates subbed once, and frees it after the last site has been parsed.
  145. **  If subbed is NULL, we don't update the SITE array, since we're just
  146. **  doing syntax checking.
  147. */
  148. STRING
  149. SITEparseone(Entry, sp, subbed)
  150.     char        *Entry;
  151.     SITE        *sp;
  152.     char        *subbed;
  153. {
  154.     static char        BATCH[] = _PATH_BATCHDIR;
  155.     register int    i;
  156.     register int    j;
  157.     register NEWSGROUP    *ngp;
  158.     register char    *p;
  159.     char        *f2;
  160.     char        *f3;
  161.     char        *f4;
  162.     char        **save;
  163.     char        **argv;
  164.     BOOL        JustModerated;
  165.     BOOL        JustUnmoderated;
  166.     int            isp;
  167.     SITE        *nsp;
  168.     BUFFER        b;
  169.  
  170.     b = sp->Buffer;
  171.     *sp = SITEnull;
  172.     sp->Buffer = b;
  173.     sp->Master = NOSITE;
  174.     sp->Funnel = NOSITE;
  175.     sp->Process = -1;
  176.     sp->Entry = Entry;
  177.     sp->FileFlags[0] = FEED_NAME;
  178.     sp->FileFlags[1] = '\0';
  179.  
  180.     /* Nip off the first field, the site name. */
  181.     if ((f2 = strchr(Entry, NF_FIELD_SEP)) == NULL)
  182.     return "missing field 2";
  183.     *f2++ = '\0';
  184.     sp->Name = Entry;
  185.     if ((p = strchr(sp->Name, NF_SUBFIELD_SEP)) != NULL) {
  186.     /* Exclusions within the site field. */
  187.     *p++ = '\0';
  188.     sp->Exclusions = CommaSplit(p);
  189.     }
  190.     sp->NameLength = strlen(sp->Name);
  191.  
  192.     /* Parse the second field, the subscriptions. */
  193.     if ((f3 = strchr(f2, NF_FIELD_SEP)) == NULL)
  194.     return "missing field 3";
  195.     *f3++ = '\0';
  196.     if ((p = strchr(f2, NF_SUBFIELD_SEP)) != NULL) {
  197.     /* Distributions within the subscription field. */
  198.     *p++ = '\0';
  199.     sp->Distributions = CommaSplit(p);
  200.     }
  201.     sp->Patterns = CommaSplit(f2);
  202.  
  203.     if (subbed) {
  204.     /* Read the subscription patterns and set the bits. */
  205.     (void)memset((POINTER)subbed, SUB_DEFAULT, (SIZE_T)nGroups);
  206.     if (ME.Patterns)
  207.         SITEsetlist(ME.Patterns, subbed);
  208.     SITEsetlist(sp->Patterns, subbed);
  209.     }
  210.  
  211.     /* Get the third field, the flags. */
  212.     if ((f4 = strchr(f3, NF_FIELD_SEP)) == NULL)
  213.     return "missing field 4";
  214.     *f4++ = '\0';
  215.     JustModerated = FALSE;
  216.     JustUnmoderated = FALSE;
  217.     sp->Type = FTfile;
  218.     for (save = argv = CommaSplit(f3); (p = *argv++) != NULL; )
  219.     switch (*p) {
  220.     default:
  221.         return "unknown field 3 flag";
  222.     case '\0':
  223.         break;
  224.     case '<':
  225.         if (*++p && CTYPE(isdigit, *p))
  226.         sp->MaxSize = atol(p);
  227.         break;
  228.     case 'A':
  229.         while (*++p)
  230.         switch (*p) {
  231.         default:
  232.             return "unknown A param in field 3";
  233.         case 'd': sp->DistRequired = TRUE;    break;
  234.         case 'p': sp->IgnorePath = TRUE;    break;
  235.         }
  236.         break;
  237.     case 'B':
  238.         if (*++p && CTYPE(isdigit, *p)) {
  239.         sp->StartWriting = atoi(p);
  240.         if ((p = strchr(p, NF_SUBFIELD_SEP)) != NULL
  241.          && *++p
  242.          && CTYPE(isdigit, *p))
  243.             sp->StopWriting = atoi(p);
  244.         }
  245.         break;
  246.     case 'F':
  247.         if (*++p == '/')
  248.         sp->SpoolName = COPY(p);
  249.         else {
  250.         sp->SpoolName = NEW(char, STRLEN(BATCH) + 1 + strlen(p) + 1);
  251.         FileGlue(sp->SpoolName, BATCH, '/', p);
  252.         }
  253.         break;
  254.     case 'G':
  255.         if (*++p && CTYPE(isdigit, *p))
  256.         sp->Groupcount = atoi(p);
  257.         else
  258.         sp->Groupcount = 1;
  259.         break;
  260.     case 'H':
  261.         if (*++p && CTYPE(isdigit, *p))
  262.         sp->Hops = atoi(p);
  263.         else
  264.         sp->Hops = 1;
  265.         break;
  266.     case 'I':
  267.         if (*++p && CTYPE(isdigit, *p))
  268.         sp->Flushpoint = atol(p);
  269.         break;
  270.     case 'N':
  271.         while (*++p)
  272.         switch (*p) {
  273.         default:
  274.             return "unknown N param in field 3";
  275.         case 'm': JustModerated = TRUE;        break;
  276.         case 'u': JustUnmoderated = TRUE;    break;
  277.         }
  278.         break;
  279.     case 'S':
  280.         if (*++p && CTYPE(isdigit, *p))
  281.         sp->StartSpooling = atol(p);
  282.         break;
  283.     case 'T':
  284.         switch (*++p) {
  285.         default:
  286.         return "unknown T param in field 3";
  287.         case 'c': sp->Type = FTchannel;    break;
  288.         case 'l': sp->Type = FTlogonly;    break;
  289.         case 'f': sp->Type = FTfile;    break;
  290.         case 'm': sp->Type = FTfunnel;    break;
  291.         case 'p': sp->Type = FTprogram;    break;
  292.         case 'x': sp->Type = FTexploder;    break;
  293.         }
  294.         break;
  295.     case 'W':
  296.         for (i = 0; *++p && i < FEED_MAXFLAGS; ) {
  297.         switch (*p) {
  298.         default:
  299.             return "unknown W param in field 3";
  300.         case FEED_FNLNAMES:        /* Funnel feed names    */
  301.             sp->FNLwantsnames = TRUE;
  302.             break;
  303.         case FEED_HEADERS:        /* Article headers    */
  304.             NeedHeaders = TRUE;
  305.             break;
  306.         case FEED_OVERVIEW:
  307.             NeedOverview = TRUE;    /* Overview data    */
  308.             break;
  309.         case FEED_BYTESIZE:        /* Size in bytes    */
  310.         case FEED_FULLNAME:        /* Full filename    */
  311.         case FEED_HDR_DISTRIB:        /* Distribution header    */
  312.         case FEED_HDR_NEWSGROUP:    /* Newsgroup header    */
  313.         case FEED_MESSAGEID:        /* Message-ID        */
  314.         case FEED_NAME:            /* Filename        */
  315.         case FEED_NEWSGROUP:        /* Newsgroup        */
  316.         case FEED_REPLIC:        /* Replication data    */
  317.         case FEED_SITE:            /* Site that gave it    */
  318.         case FEED_TIMERECEIVED:        /* When received    */
  319.             break;
  320.         }
  321.         sp->FileFlags[i++] = *p;
  322.         }
  323.         if (*p)
  324.         return "too many W param values";
  325.         sp->FileFlags[i] = '\0';
  326.         break;
  327.     }
  328.     DISPOSE(save);
  329.     if (sp->Flushpoint && sp->Type != FTfile)
  330.     return "I param with non-file feed";
  331.  
  332.     if (subbed) {
  333.     /* Modify the subscription list based on the flags. */
  334.     if (JustModerated)
  335.         for (p = subbed, ngp = Groups, i = nGroups; --i >= 0; ngp++, p++)
  336.         if (ngp->Rest[0] != NF_FLAG_MODERATED)
  337.             *p = FALSE;
  338.     if (JustUnmoderated)
  339.         for (p = subbed, ngp = Groups, i = nGroups; --i >= 0; ngp++, p++)
  340.         if (ngp->Rest[0] == NF_FLAG_MODERATED)
  341.             *p = FALSE;
  342.     }
  343.  
  344.     /* Get the fourth field, the param. */
  345.     if (*f4 == '\0' && sp != &ME) {
  346.     if (sp->Type != FTfile && sp->Type != FTlogonly)
  347.         return "empty field 4";
  348.     sp->Param = NEW(char, STRLEN(BATCH) + 1 + sp->NameLength + 1);
  349.     FileGlue(sp->Param, BATCH, '/', sp->Name);
  350.     }
  351.     else if (sp->Type == FTfile && *f4 != '/') {
  352.     sp->Param = NEW(char, STRLEN(BATCH) + 1 + strlen(f4) + 1);
  353.     FileGlue(sp->Param, BATCH, '/', f4);
  354.     }
  355.     else
  356.     sp->Param = COPY(f4);
  357.  
  358.     if (sp->SpoolName == NULL) {
  359.     sp->SpoolName = NEW(char, STRLEN(BATCH) + 1 + strlen(sp->Name) + 1);
  360.     FileGlue(sp->SpoolName, BATCH, '/', sp->Name);
  361.     }
  362.  
  363.     /* Make sure there is only one %s, and only one *. */
  364.     if (sp->Type == FTprogram) {
  365.     if ((p = strchr(sp->Param, '%')) != NULL) {
  366.         while (*++p && *p != '*' && !CTYPE(isalpha, *p))
  367.         continue;
  368.         if (*p != 's' || strchr(p, '%') != NULL)
  369.         return "bad sprintf format for field 4";
  370.     }
  371.     if (sp->FNLwantsnames
  372.      && ((p = strchr(sp->Param, '*')) == NULL
  373.       || strchr(++p, '*') != NULL))
  374.         return "multiple or no *'s in field 4";
  375.     }
  376.  
  377.     /* Now tell the groups this site gets that they should feed this site. */
  378.     if (sp != &ME && subbed) {
  379.     isp = sp - Sites;
  380.     for (p = subbed, ngp = Groups, i = nGroups; --i >= 0; ngp++)
  381.         if (*p++) {
  382.         for (j = 0; j < ngp->nSites; j++)
  383.             if (ngp->Sites[j] == NOSITE) {
  384.             ngp->Sites[j] = isp;
  385.             break;
  386.             }
  387.         if (j == ngp->nSites)
  388.             ngp->Sites[ngp->nSites++] = isp;
  389.         }
  390.     }
  391.  
  392.     /* If this is a duplicate name, find the master. */
  393.     nsp = SITEfind(sp->Name);
  394.     if (nsp == sp)
  395.     nsp = SITEfindnext(sp->Name, nsp);
  396.     if (nsp != NULL) {
  397.     if (nsp->Master != NOSITE)
  398.         nsp = &Sites[nsp->Master];
  399.     if (nsp != sp) {
  400.         sp->Master = nsp - Sites;
  401.         nsp->IsMaster = TRUE;
  402.     }
  403.     }
  404.  
  405.     return NULL;
  406. }
  407.  
  408.  
  409. /*
  410. **  Patch up the funnel references.
  411. */
  412. BOOL
  413. SITEfunnelpatch()
  414. {
  415.     register int    i;
  416.     register int    length;
  417.     register SITE    *sp;
  418.     SITE        *funnel;
  419.     BOOL        result;
  420.  
  421.     /* Get worst-case length of all sitenames. */
  422.     for (length = 0, i = nSites, sp = Sites; --i >= 0; sp++)
  423.     if (sp->Name != NULL)
  424.         length += 1 + strlen(sp->Name);
  425.  
  426.     /* Loop over all funnel feeds. */
  427.     for (result = TRUE, i = nSites, sp = Sites; --i >= 0; sp++) {
  428.     if (sp->Type != FTfunnel)
  429.         continue;
  430.  
  431.     /* Find the entry they feed in to, give that entry a buffer. */
  432.     if (sp->Param == NULL) {
  433.         syslog(L_FATAL, "%s funnel NULL", sp->Name);
  434.         SITEfree(sp);
  435.         result = FALSE;
  436.         continue;
  437.     }
  438.     if ((funnel = SITEfind(sp->Param)) == NULL) {
  439.         syslog(L_FATAL, "%s funnel_bad", sp->Name);
  440.         SITEfree(sp);
  441.         result = FALSE;
  442.         continue;
  443.     }
  444.     if (funnel->Type == FTfunnel) {
  445.         syslog(L_FATAL, "%s funnels to funnel %s", sp->Name, funnel->Name);
  446.         SITEfree(sp);
  447.         result = FALSE;
  448.         continue;
  449.     }
  450.     if (funnel->FNLnames.Data == NULL) {
  451.         funnel->FNLnames.Size = length;
  452.         funnel->FNLnames.Data = NEW(char, length);
  453.     }
  454.     else if (funnel->FNLnames.Size != length) {
  455.         funnel->FNLnames.Size = length;
  456.         RENEW(funnel->FNLnames.Data, char, length);
  457.     }
  458.     sp->Funnel = funnel - Sites;
  459.     }
  460.  
  461.     return result;
  462. }
  463.  
  464.  
  465. /*
  466. **  Read the entries in the newsfeeds file, and parse them one at a time.
  467. */
  468. void
  469. SITEparsefile(StartSite)
  470.     BOOL        StartSite;
  471. {
  472.     register int    i;
  473.     register char    *p;
  474.     char        **strings;
  475.     SITE        *sp;
  476.     char        *subbed;
  477.     STRING        error;
  478.     int            errors;
  479.  
  480.     /* Free old sites info. */
  481.     if (Sites) {
  482.     for (i = nSites, sp = Sites; --i >= 0; sp++) {
  483.         SITEflush(sp, FALSE);
  484.         SITEfree(sp);
  485.     }
  486.     DISPOSE(Sites);
  487.     SITEfree(&ME);
  488.     }
  489.  
  490.     /* Count the number of sites. */
  491.     for (strings = SITEreadfile(FALSE), nSites = 0; strings[nSites]; nSites++)
  492.     continue;
  493.     Sites = NEW(SITE, nSites);
  494.     for (sp = Sites, i = 0; i < nSites; i++, sp++) {
  495.     sp->Name = NULL;
  496.     sp->Buffer.Data = NULL;
  497.     }
  498.  
  499.     /* Set up scratch subscription list. */
  500.     subbed = NEW(char, nGroups);
  501.  
  502.     for (sp = Sites, errors = 0, i = 0; i < nSites; i++) {
  503.     p = strings[i];
  504.     if (p[0] == 'M' && p[1] == 'E' && p[2] == NF_FIELD_SEP) {
  505.         if ((error = SITEparseone(p, &ME, subbed)) != NULL) {
  506.         syslog(L_FATAL, "%s bad_newsfeeds %s", MaxLength(p, p), error);
  507.         errors++;
  508.         }
  509.         continue;
  510.     }
  511.     if ((error = SITEparseone(p, sp, subbed)) != NULL) {
  512.         syslog(L_FATAL, "%s bad_newsfeeds %s", MaxLength(p, p), error);
  513.         errors++;
  514.         continue;
  515.     }
  516.     if (StartSite && !SITEsetup(sp)) {
  517.         syslog(L_FATAL, "%s cant setup %m", sp->Name);
  518.         errors++;
  519.         continue;
  520.     }
  521.     sp->Working = TRUE;
  522.     sp++;
  523.     }
  524.  
  525.     if (errors) {
  526.     syslog(L_FATAL, "%s syntax_error %s", LogName, SITEfeedspath);
  527.     JustCleanup();
  528.     exit(1);
  529.     }
  530.  
  531.     /* Free our scratch array, set up the funnel links. */
  532.     nSites = sp - Sites;
  533.     DISPOSE(subbed);
  534.     DISPOSE(strings);
  535.     if (!SITEfunnelpatch()) {
  536.     JustCleanup();
  537.     exit(1);
  538.     }
  539.     SITElinkall();
  540. }
  541.